using System;
using Mbs.ComponentModel.Container.Context;
using Mbs.ComponentModel.Container.Injection;
using Mbs.ComponentModel.Container.Metadata;

namespace Mbs.ComponentModel.Container.Activation
{
    [Serializable]
    public abstract class AbstractActivator : MarshalAndDisposableObject, IActivator
    {
        private readonly object SyncRoot = new object();
        public virtual void Init(Action<IComponentInfo, object> onCreation)
        {
            this.OnCreation = onCreation;
        }

        protected Action<IComponentInfo, object> OnCreation { get; private set; }

        protected IKernel Kernel { get; private set; }
        protected ICreateContext Context { get; private set; }

        private bool hasLock;

        public virtual object Create(ICreateContext context)
        {
            if (hasLock)
                throw new LoopDependencyException("loop inject error the inject object is " + context.Component.ToString());

            object instance = null;

            lock (SyncRoot)
            {
                hasLock = true;

                Kernel = context.Kernel as IKernel;
                Context = context;

                //Create instance
                instance = InternalCreate(context);

                //Inject members 
                Kernel.InjectStrategyManager.Execute(new InspectContext(Kernel, context.Component, instance));

                //raise on creation event
                if (OnCreation != null && instance != null)
                    OnCreation(context.Component, instance);
            }

            hasLock = false;

            return instance;
        }

        protected abstract object InternalCreate(ICreateContext context);
    }
}
